/**
 * @file   Value.h
 * @author Djuro Drljaca (djurodrljaca@gmail.com)
 * @date   2013-05-03
 * @brief  DataBus Value.
 *
 * Copyright (C) 2013  Djuro Drljaca <djurodrljaca@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef LIBDATABUS_COMMON_VALUE_H
#define LIBDATABUS_COMMON_VALUE_H

#include <DataBus/Common/PacketHeader.h>
#include <DataBus/Common/PacketPayload.h>
#include <QtCore/QString>

namespace DataBus
{
/**
 * @brief The Value class
 */
class DATABUSSHARED_EXPORT Value
{
public:
    /**
     * @brief Constructor for Value
     */
    Value();

    /**
     * @brief Constructor for Value
     *
     * @param value Boolean value
     */
    Value(const bool value);

    /**
     * @brief Constructor for Value
     *
     * @param value Signed 8-bit integer value
     */
    Value(const qint8 value);

    /**
     * @brief Constructor for Value
     *
     * @param value Unsigned 8-bit integer value
     */
    Value(const quint8 value);

    /**
     * @brief Constructor for Value
     *
     * @param value Signed 16-bit integer value
     */
    Value(const qint16 value);

    /**
     * @brief Constructor for Value
     *
     * @param value Unsigned 16-bit integer value
     */
    Value(const quint16 value);

    /**
     * @brief Constructor for Value
     *
     * @param value Signed 32-bit integer value
     */
    Value(const qint32 value);

    /**
     * @brief Constructor for Value
     *
     * @param value Unsigned 32-bit integer value
     */
    Value(const quint32 value);

    /**
     * @brief Constructor for Value
     *
     * @param value Signed 64-bit integer value
     */
    Value(const qint64 value);

    /**
     * @brief Constructor for Value
     *
     * @param value Unsigned 64-bit integer value
     */
    Value(const quint64 value);

    /**
     * @brief Constructor for Value
     *
     * @param value Floating-point value (32-bit) value
     */
    Value(const float value);

    /**
     * @brief Constructor for Value
     *
     * @param value Double floating-point value (64-bit) value
     */
    Value(const double value);

    /**
     * @brief Constructor for Value
     *
     * @param value String (UTF-8 encoding)
     */
    Value(const QString &value);

    /**
     * @brief Constructor for Value
     *
     * @param value Byte Array
     */
    Value(const QByteArray &value);

    /**
     * @brief Copy constructor for Value
     *
     * @param copyin    Original value
     */
    Value(const Value &copyin);

    /**
     * @brief Destructor for Value
     */
    ~Value();

    /**
     * @brief Operator =
     *
     * @param rhs   Value on the right side of the operator =
     *
     * @return Value
     */
    Value & operator=(const Value &rhs);

    /**
     * @brief Get Data Type
     *
     * @return Data type
     */
    DataType getDataType() const;

    /**
     * @brief Get Boolean Value
     *
     * @return Boolean value
     */
    bool getBoolean() const;

    /**
     * @brief Set Value
     *
     * @param value Boolean value
     */
    void setBoolean(const bool value);

    /**
     * @brief Get Signed 8-bit integer Value
     *
     * @return Signed 8-bit integer value
     */
    qint8 getInt8() const;

    /**
     * @brief Set Value
     *
     * @param value Signed 8-bit integer value
     */
    void setInt8(const qint8 value);

    /**
     * @brief Get Unsigned 8-bit integer Value
     *
     * @return Unsigned 8-bit integer value
     */
    quint8 getUInt8() const;

    /**
     * @brief Set Value
     *
     * @param value Unsigned 8-bit integer value
     */
    void setUInt8(const quint8 value);

    /**
     * @brief Get Signed 16-bit integer Value
     *
     * @return Signed 16-bit integer value
     */
    qint16 getInt16() const;

    /**
     * @brief Set Value
     *
     * @param value Signed 16-bit integer value
     */
    void setInt16(const qint16 value);

    /**
     * @brief Get Unsigned 16-bit integer Value
     *
     * @return Unsigned 16-bit integer value
     */
    quint16 getUInt16() const;

    /**
     * @brief Set Value
     *
     * @param value Unsigned 16-bit integer value
     */
    void setUInt16(const quint16 value);

    /**
     * @brief Get Signed 32-bit integer Value
     *
     * @return Signed 32-bit integer value
     */
    qint32 getInt32() const;

    /**
     * @brief Set Value
     *
     * @param value Signed 32-bit integer value
     */
    void setInt32(const qint32 value);

    /**
     * @brief Get Unsigned 32-bit integer Value
     *
     * @return Unsigned 32-bit integer value
     */
    quint32 getUInt32() const;

    /**
     * @brief Set Value
     *
     * @param value Unsigned 32-bit integer value
     */
    void setUInt32(const quint32 value);

    /**
     * @brief Get Signed 64-bit integer Value
     *
     * @return Signed 64-bit integer value
     */
    qint64 getInt64() const;

    /**
     * @brief Set Value
     *
     * @param value Signed 64-bit integer value
     */
    void setInt64(const qint64 value);

    /**
     * @brief Get Unsigned 64-bit integer Value
     *
     * @return Unsigned 64-bit integer value
     */
    quint64 getUInt64() const;

    /**
     * @brief Set Value
     *
     * @param value Unsigned 64-bit integer value
     */
    void setUInt64(const quint64 value);

    /**
     * @brief Get Floating-point value (32-bit) Value
     *
     * @return Floating-point value (32-bit) value
     */
    float getFloat() const;

    /**
     * @brief Set Value
     *
     * @param value Floating-point value (32-bit) value
     */
    void setFloat(const float value);

    /**
     * @brief Get Double floating-point value (64-bit) Value
     *
     * @return Double floating-point value (64-bit) value
     */
    double getDouble() const;

    /**
     * @brief Set Value
     *
     * @param value Double floating-point value (64-bit) value
     */
    void setDouble(const double value);

    /**
     * @brief Get String (UTF-8 encoding) Value
     *
     * @return String (UTF-8 encoding) value
     */
    QString getString() const;

    /**
     * @brief Set Value
     *
     * @param value String (UTF-8 encoding)
     */
    void setString(const QString &value);

    /**
     * @brief Get Byte Array Value
     *
     * @return Byte Array value
     */
    QByteArray getByteArray() const;

    /**
     * @brief Set Value
     *
     * @param value Byte Array
     */
    void setByteArray(const QByteArray &value);

    /**
     * @brief Checks if value is valid
     *
     * @retval true     Value is valid
     * @retval false    Value is not valid
     */
    bool isValid() const;

    /**
     * @brief Convert value to binary (byte array)
     *
     * @return Byte array with binary representation of Value
     */
    QByteArray toBinary() const;

    /**
     * @brief Convert value to binary (byte array)
     *
     * @param value Input value
     *
     * @return Byte array with binary representation of Value
     */
    static QByteArray toBinary(const bool value);

    /**
     * @brief Convert value to binary (byte array)
     *
     * @param value Input value
     *
     * @return Byte array with binary representation of Value
     */
    static QByteArray toBinary(const qint8 value);

    /**
     * @brief Convert value to binary (byte array)
     *
     * @param value Input value
     *
     * @return Byte array with binary representation of Value
     */
    static QByteArray toBinary(const quint8 value);

    /**
     * @brief Convert value to binary (byte array)
     *
     * @param value Input value
     *
     * @return Byte array with binary representation of Value
     */
    static QByteArray toBinary(const qint16 value);

    /**
     * @brief Convert value to binary (byte array)
     *
     * @param value Input value
     *
     * @return Byte array with binary representation of Value
     */
    static QByteArray toBinary(const quint16 value);

    /**
     * @brief Convert value to binary (byte array)
     *
     * @param value Input value
     *
     * @return Byte array with binary representation of Value
     */
    static QByteArray toBinary(const qint32 value);

    /**
     * @brief Convert value to binary (byte array)
     *
     * @param value Input value
     *
     * @return Byte array with binary representation of Value
     */
    static QByteArray toBinary(const quint32 value);

    /**
     * @brief Convert value to binary (byte array)
     *
     * @param value Input value
     *
     * @return Byte array with binary representation of Value
     */
    static QByteArray toBinary(const qint64 value);

    /**
     * @brief Convert value to binary (byte array)
     *
     * @param value Input value
     *
     * @return Byte array with binary representation of Value
     */
    static QByteArray toBinary(const quint64 value);

    /**
     * @brief Convert value to binary (byte array)
     *
     * @param value Input value
     *
     * @return Byte array with binary representation of Value
     */
    static QByteArray toBinary(const float value);

    /**
     * @brief Convert value to binary (byte array)
     *
     * @param value Input value
     *
     * @return Byte array with binary representation of Value
     */
    static QByteArray toBinary(const double value);

    /**
     * @brief Convert value to binary (byte array)
     *
     * @param value Input value
     *
     * @return Byte array with binary representation of Value
     */
    static QByteArray toBinary(const QString &value);

    /**
     * @brief Convert value to binary (byte array)
     *
     * @param value Input value
     *
     * @return Byte array with binary representation of Value
     */
    static QByteArray toBinary(const QByteArray &value);

    /**
     * @brief Parse value from binary (byte array)
     *
     * @param data          Binary data
     * @param dataType      Data type
     * @param startIndex    Start index of binary data
     *
     * @retval true     Success
     * @retval false    Error
     */
    bool fromBinary(const QByteArray &data, const DataType dataType, const int startIndex = 0);

    /**
     * @brief Parse value from binary (byte array)
     *
     * @param data          Binary data
     * @param[out] value    Parsed value
     * @param startIndex    Start index of binary data
     *
     * @retval true     Success
     * @retval false    Error
     */
    static bool fromBinary(const QByteArray &data, bool *value, const int startIndex = 0);

    /**
     * @brief Parse value from binary (byte array)
     *
     * @param data          Binary data
     * @param[out] value    Parsed value
     * @param startIndex    Start index of binary data
     *
     * @retval true     Success
     * @retval false    Error
     */
    static bool fromBinary(const QByteArray &data, qint8 *value, const int startIndex = 0);

    /**
     * @brief Parse value from binary (byte array)
     *
     * @param data          Binary data
     * @param[out] value    Parsed value
     * @param startIndex    Start index of binary data
     *
     * @retval true     Success
     * @retval false    Error
     */
    static bool fromBinary(const QByteArray &data, quint8 *value, const int startIndex = 0);

    /**
     * @brief Parse value from binary (byte array)
     *
     * @param data          Binary data
     * @param[out] value    Parsed value
     * @param startIndex    Start index of binary data
     *
     * @retval true     Success
     * @retval false    Error
     */
    static bool fromBinary(const QByteArray &data, qint16 *value, const int startIndex = 0);

    /**
     * @brief Parse value from binary (byte array)
     *
     * @param data          Binary data
     * @param[out] value    Parsed value
     * @param startIndex    Start index of binary data
     *
     * @retval true     Success
     * @retval false    Error
     */
    static bool fromBinary(const QByteArray &data, quint16 *value, const int startIndex = 0);

    /**
     * @brief Parse value from binary (byte array)
     *
     * @param data          Binary data
     * @param[out] value    Parsed value
     * @param startIndex    Start index of binary data
     *
     * @retval true     Success
     * @retval false    Error
     */
    static bool fromBinary(const QByteArray &data, qint32 *value, const int startIndex = 0);

    /**
     * @brief Parse value from binary (byte array)
     *
     * @param data          Binary data
     * @param[out] value    Parsed value
     * @param startIndex    Start index of binary data
     *
     * @retval true     Success
     * @retval false    Error
     */
    static bool fromBinary(const QByteArray &data, quint32 *value, const int startIndex = 0);

    /**
     * @brief Parse value from binary (byte array)
     *
     * @param data          Binary data
     * @param[out] value    Parsed value
     * @param startIndex    Start index of binary data
     *
     * @retval true     Success
     * @retval false    Error
     */
    static bool fromBinary(const QByteArray &data, qint64 *value, const int startIndex = 0);

    /**
     * @brief Parse value from binary (byte array)
     *
     * @param data          Binary data
     * @param[out] value    Parsed value
     * @param startIndex    Start index of binary data
     *
     * @retval true     Success
     * @retval false    Error
     */
    static bool fromBinary(const QByteArray &data, quint64 *value, const int startIndex = 0);

    /**
     * @brief Parse value from binary (byte array)
     *
     * @param data          Binary data
     * @param[out] value    Parsed value
     * @param startIndex    Start index of binary data
     *
     * @retval true     Success
     * @retval false    Error
     */
    static bool fromBinary(const QByteArray &data, float *value, const int startIndex = 0);

    /**
     * @brief Parse value from binary (byte array)
     *
     * @param data          Binary data
     * @param[out] value    Parsed value
     * @param startIndex    Start index of binary data
     *
     * @retval true     Success
     * @retval false    Error
     */
    static bool fromBinary(const QByteArray &data, double *value, const int startIndex = 0);

    /**
     * @brief Parse value from binary (byte array)
     *
     * @param data          Binary data
     * @param[out] value    Parsed value
     * @param startIndex    Start index of binary data
     *
     * @retval true     Success
     * @retval false    Error
     */
    static bool fromBinary(const QByteArray &data, QString *value, const int startIndex = 0);

    /**
     * @brief Parse value from binary (byte array)
     *
     * @param data          Binary data
     * @param[out] value    Parsed value
     * @param startIndex    Start index of binary data
     *
     * @retval true     Success
     * @retval false    Error
     */
    static bool fromBinary(const QByteArray &data, QByteArray *value, const int startIndex = 0);

private:
    /**
     * @brief Generic value
     */
    union
    {
        bool valueBoolean;

        qint8 valueInt8;
        quint8 valueUInt8;

        qint16 valueInt16;
        quint16 valueUInt16;

        qint32 valueInt32;
        quint32 valueUInt32;

        qint64 valueInt64;
        quint64 valueUInt64;

        float valueFloat;
        double valueDouble;

        QString *valueString;
        QByteArray *valueByteArray;
    } m_value;

    /**
     * @brief Actual data type
     */
    DataType m_dataType;
};
}

#endif // LIBDATABUS_COMMON_VALUE_H
